package com.dms.modules.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.dms.common.exception.BusinessException;
import com.dms.modules.product.dto.ProductSkuDTO;
import com.dms.modules.product.entity.Product;
import com.dms.modules.product.entity.ProductSku;
import com.dms.modules.product.mapper.ProductSkuMapper;
import com.dms.modules.product.service.ProductFacade;
import com.dms.modules.product.service.ProductService;
import com.dms.modules.product.service.ProductSkuService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;

@Slf4j
@Service
public class ProductSkuServiceImpl extends BaseProductServiceImpl<ProductSkuMapper, ProductSku> implements ProductSkuService {

    @Autowired
    @Lazy
    private ProductFacade productFacade;
    
    @Autowired
    @Lazy
    private ProductService productService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean create(ProductSkuDTO skuDTO) {
        // 自动生成SKU编码
        String skuCode = generateSkuCode(skuDTO);
        skuDTO.setSkuCode(skuCode);

        ProductSku sku = new ProductSku();
        // 手动设置字段
        sku.setProductId(skuDTO.getProductId());
        sku.setSkuCode(skuDTO.getSkuCode());
        sku.setSkuName(skuDTO.getSkuName());
        sku.setSpecValues(skuDTO.getSpecValues());
        sku.setImage(skuDTO.getImage());
        sku.setPrice(skuDTO.getPrice());
        sku.setStock(skuDTO.getStock());
        sku.setStatus(1);  // 默认启用
        sku.setAdminStatus(1);  // 默认管理员状态为启用
        sku.setSales(0);  // 初始销量为0

        boolean success = save(sku);
        if (success) {
            // 更新商品总库存
            productService.updateTotalStock(sku.getProductId());
            
            // 更新商品主表最低价格
            List<ProductSku> skuList = getByProductId(sku.getProductId());
            if (!skuList.isEmpty()) {
                BigDecimal minPrice = skuList.stream()
                        .map(ProductSku::getPrice)
                        .min(BigDecimal::compareTo)
                        .orElse(BigDecimal.ZERO);
                productService.lambdaUpdate()
                        .eq(Product::getId, sku.getProductId())
                        .set(Product::getPrice, minPrice)
                        .update();
            }
        }
        return success;
    }

    /**
     * 生成SKU编码
     * 规则：商品ID + 时间戳 + 规格值的哈希值 + 随机数
     */
    private String generateSkuCode(ProductSkuDTO skuDTO) {
        String specValues = skuDTO.getSpecValues();
        String hashCode = String.valueOf(Math.abs(specValues.hashCode()));
        String timestamp = String.valueOf(System.currentTimeMillis() % 10000); // 取后4位
        String random = String.valueOf((int)(Math.random() * 1000)); // 3位随机数
        return String.format("P%d-%s-%s-%s", 
            skuDTO.getProductId(), 
            timestamp,
            hashCode,
            random);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(ProductSkuDTO skuDTO) {
        // 验证SKU编码是否存在
        if (existsSkuCode(skuDTO.getSkuCode(), skuDTO.getId())) {
            throw new BusinessException("SKU编码已存在");
        }

        ProductSku sku = new ProductSku();
        BeanUtils.copyProperties(skuDTO, sku);
        boolean success = updateById(sku);
        
        if (success) {
            // 如果更新了价格或库存，同步更新商品主表
            ProductSku oldSku = getById(skuDTO.getId());
            if (oldSku != null && (
                !oldSku.getPrice().equals(sku.getPrice()) || 
                !oldSku.getStock().equals(sku.getStock()))) {
                    
                // 更新商品总库存
                productService.updateTotalStock(sku.getProductId());
                
                // 更新商品主表最低价格
                List<ProductSku> skuList = getByProductId(sku.getProductId());
                if (!skuList.isEmpty()) {
                    BigDecimal minPrice = skuList.stream()
                            .map(ProductSku::getPrice)
                            .min(BigDecimal::compareTo)
                            .orElse(BigDecimal.ZERO);
                    productService.lambdaUpdate()
                            .eq(Product::getId, sku.getProductId())
                            .set(Product::getPrice, minPrice)
                            .update();
                }
            }
        }
        return success;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(List<Long> skuIds, Integer status) {
        if (skuIds == null || skuIds.isEmpty()) {
            return false;
        }
        return lambdaUpdate()
                .set(ProductSku::getStatus, status)
                .in(ProductSku::getId, skuIds)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePrices(Map<Long, BigDecimal> skuPriceMap) {
        if (skuPriceMap == null || skuPriceMap.isEmpty()) {
            return false;
        }

        // 按商品ID分组更新
        Map<Long, List<Long>> productSkuMap = new HashMap<>();
        for (Long skuId : skuPriceMap.keySet()) {
            ProductSku sku = getById(skuId);
            if (sku != null) {
                productSkuMap.computeIfAbsent(sku.getProductId(), k -> new ArrayList<>()).add(skuId);
            }
        }

        // 更新SKU价格
        for (Map.Entry<Long, BigDecimal> entry : skuPriceMap.entrySet()) {
            lambdaUpdate()
                    .eq(ProductSku::getId, entry.getKey())
                    .set(ProductSku::getPrice, entry.getValue())
                    .update();
        }

        // 更新商品主表价格（取最低价）
        for (Long productId : productSkuMap.keySet()) {
            List<ProductSku> skuList = getByProductId(productId);
            if (!skuList.isEmpty()) {
                BigDecimal minPrice = skuList.stream()
                        .map(ProductSku::getPrice)
                        .min(BigDecimal::compareTo)
                        .orElse(BigDecimal.ZERO);
                productService.lambdaUpdate()
                        .eq(Product::getId, productId)
                        .set(Product::getPrice, minPrice)
                        .update();
            }
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStocks(Map<Long, Integer> skuStockMap) {
        if (skuStockMap == null || skuStockMap.isEmpty()) {
            return false;
        }

        // 按商品ID分组更新
        Map<Long, List<Long>> productSkuMap = new HashMap<>();
        for (Long skuId : skuStockMap.keySet()) {
            ProductSku sku = getById(skuId);
            if (sku != null) {
                productSkuMap.computeIfAbsent(sku.getProductId(), k -> new ArrayList<>()).add(skuId);
            }
        }

        // 更新SKU库存
        for (Map.Entry<Long, Integer> entry : skuStockMap.entrySet()) {
            lambdaUpdate()
                    .eq(ProductSku::getId, entry.getKey())
                    .set(ProductSku::getStock, entry.getValue())
                    .update();
        }

        // 更新商品主表库存（所有SKU库存之和）
        for (Long productId : productSkuMap.keySet()) {
            productService.updateTotalStock(productId);
        }

        return true;
    }

    @Override
    public IPage<ProductSku> pageSkus(Page<ProductSku> page, Long productId, Integer status) {
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductSku::getProductId, productId);
        if (status != null) {
            wrapper.eq(ProductSku::getStatus, status);
        }
        return page(page, wrapper);
    }

    @Override
    public List<ProductSku> getByProductId(Long productId) {
        if (productId == null) {
            throw new BusinessException("商品ID不能为空");
        }
        
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductSku::getProductId, productId)
               .orderByAsc(ProductSku::getId);
        return list(wrapper);
    }

    @Override
    public List<ProductSku> listByProductIds(List<Long> productIds) {
        if (productIds == null || productIds.isEmpty()) {
            return Collections.emptyList();
        }
        
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ProductSku::getProductId, productIds)
               .orderByAsc(ProductSku::getProductId, ProductSku::getId);
        return list(wrapper);
    }

    @Override
    public boolean existsSkuCode(String skuCode, Long excludeId) {
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductSku::getSkuCode, skuCode);
        if (excludeId != null) {
            wrapper.ne(ProductSku::getId, excludeId);
        }
        return baseMapper.exists(wrapper);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected <R> SFunction<ProductSku, R> getFieldFunction(String fieldName) {
        switch (fieldName) {
            case "id":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, Long>) ProductSku::getId;
            case "productId":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, Long>) ProductSku::getProductId;
            case "skuCode":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, String>) ProductSku::getSkuCode;
            case "price":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, BigDecimal>) ProductSku::getPrice;
            case "stock":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, Integer>) ProductSku::getStock;
            case "status":
                return (SFunction<ProductSku, R>) (SFunction<ProductSku, Integer>) ProductSku::getStatus;
            default:
                return null;
        }
    }

    @Override
    protected SFunction<ProductSku, Long> getIdField() {
        return ProductSku::getId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocateStock(Long skuId, Integer quantity) {
        // 使用乐观锁更新库存
        boolean success = lambdaUpdate()
                .setSql("stock = stock - " + quantity)
                .setSql("pre_allocated_stock = pre_allocated_stock + " + quantity)
                .eq(ProductSku::getId, skuId)
                .ge(ProductSku::getStock, quantity)
                .update();
                
        if (!success) {
            throw new BusinessException("库存不足或SKU不存在");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void releaseStock(Long skuId, Integer quantity) {
        // 使用乐观锁更新库存
        boolean success = lambdaUpdate()
                .setSql("stock = stock + " + quantity)
                .setSql("pre_allocated_stock = pre_allocated_stock - " + quantity)
                .eq(ProductSku::getId, skuId)
                .ge(ProductSku::getPreAllocatedStock, quantity)
                .update();
                
        if (!success) {
            throw new BusinessException("预分配库存不足或SKU不存在");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatch(List<ProductSku> skuList) {
        if (skuList == null || skuList.isEmpty()) {
            return true;
        }
        return super.saveBatch(skuList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByProductId(Long productId) {
        if (productId == null) {
            throw new BusinessException("商品ID不能为空");
        }
        
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductSku::getProductId, productId);
        return remove(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStock(Long skuId, Integer quantity) {
        if (skuId == null) {
            throw new BusinessException("SKU ID不能为空");
        }
        if (quantity == null) {
            throw new BusinessException("库存变化量不能为空");
        }
        
        ProductSku sku = getById(skuId);
        if (sku == null) {
            throw new BusinessException("SKU不存在");
        }
        
        // 如果是减库存，检查库存是否足够
        if (quantity < 0 && sku.getStock() + quantity < 0) {
            throw new BusinessException("库存不足");
        }
        
        boolean success = lambdaUpdate()
                .eq(ProductSku::getId, skuId)
                .setSql("stock = stock + " + quantity)
                .update();
                
        if (success) {
            // 更新商品总库存
            productService.updateTotalStock(sku.getProductId());
        }
        
        return success;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createMerchantSku(ProductSkuDTO skuDTO) {
        // 验证商品是否属于当前商家
        checkProductBelongsToMerchant(skuDTO.getProductId(), skuDTO.getMerchantId());
        return create(skuDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMerchantSku(ProductSkuDTO skuDTO) {
        // 验证SKU是否属于当前商家
        checkSkuBelongsToMerchant(skuDTO.getId(), skuDTO.getMerchantId());
        return update(skuDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMerchantPrices(Long merchantId, Map<Long, BigDecimal> skuPriceMap) {
        if (skuPriceMap == null || skuPriceMap.isEmpty()) {
            return false;
        }
        
        // 验证所有SKU是否属于当前商家
        for (Long skuId : skuPriceMap.keySet()) {
            checkSkuBelongsToMerchant(skuId, merchantId);
        }
        
        return updatePrices(skuPriceMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMerchantStocks(Long merchantId, Map<Long, Integer> skuStockMap) {
        if (skuStockMap == null || skuStockMap.isEmpty()) {
            return false;
        }
        
        // 验证所有SKU是否属于当前商家
        for (Long skuId : skuStockMap.keySet()) {
            checkSkuBelongsToMerchant(skuId, merchantId);
        }
        
        return updateStocks(skuStockMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMerchantStatus(Long merchantId, Map<Long, Integer> statusMap) {
        if (statusMap == null || statusMap.isEmpty()) {
            return false;
        }
        
        // 验证所有SKU是否属于当前商家
        for (Long skuId : statusMap.keySet()) {
            checkSkuBelongsToMerchant(skuId, merchantId);
        }
        
        return lambdaUpdate()
                .in(ProductSku::getId, statusMap.keySet())
                .set(ProductSku::getStatus, statusMap.values().iterator().next())
                .update();
    }

    @Override
    public IPage<ProductSku> pageMerchantSkus(Page<ProductSku> page, Long merchantId, Long productId, Integer status) {
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        
        // 如果指定了商品ID，先验证商品是否属于当前商家
        if (productId != null) {
            if (!productFacade.checkProductBelongsToMerchant(productId, merchantId)) {
                throw new BusinessException("商品不属于当前商家");
            }
            wrapper.eq(ProductSku::getProductId, productId);
        }
        
        if (status != null) {
            wrapper.eq(ProductSku::getStatus, status);
        }
        
        wrapper.orderByDesc(ProductSku::getCreateTime);
        return page(page, wrapper);
    }

    /**
     * 检查商品是否属于指定商家
     */
    private void checkProductBelongsToMerchant(Long productId, Long merchantId) {
        log.debug("Checking if product {} belongs to merchant {}", productId, merchantId);
        
        if (productId == null) {
            throw new BusinessException("商品ID不能为空");
        }
        if (merchantId == null) {
            throw new BusinessException("商家ID不能为空");
        }

        Product product = productService.getById(productId);
        if (product == null) {
            throw new BusinessException("商品不存在");
        }

        log.debug("Product merchantId: {}, checking merchantId: {}", product.getMerchantId(), merchantId);
        
        if (!merchantId.equals(product.getMerchantId())) {
            throw new BusinessException("商品不属于当前商家");
        }
    }

    /**
     * 检查SKU是否属于指定商家
     */
    private void checkSkuBelongsToMerchant(Long skuId, Long merchantId) {
        log.debug("Checking if SKU {} belongs to merchant {}", skuId, merchantId);
        
        if (skuId == null) {
            throw new BusinessException("SKU ID不能为空");
        }
        if (merchantId == null) {
            throw new BusinessException("商家ID不能为空");
        }

        ProductSku sku = getById(skuId);
        if (sku == null) {
            throw new BusinessException("SKU不存在");
        }
        
        log.debug("SKU found: {}, productId: {}", skuId, sku.getProductId());
        checkProductBelongsToMerchant(sku.getProductId(), merchantId);
    }

    @Override
    public IPage<ProductSku> pageSkus(Page<ProductSku> page, Long productId, Long merchantId, Integer status) {
        LambdaQueryWrapper<ProductSku> wrapper = new LambdaQueryWrapper<>();
        if (productId != null) {
            wrapper.eq(ProductSku::getProductId, productId);
        }
        if (merchantId != null) {
            wrapper.inSql(ProductSku::getProductId, 
                "select id from product where merchant_id = " + merchantId);
        }
        if (status != null) {
            wrapper.eq(ProductSku::getStatus, status);
        }
        wrapper.orderByDesc(ProductSku::getCreateTime);
        return baseMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateSkuStatus(Long id, Boolean enabled) {
        ProductSku sku = baseMapper.selectById(id);
        if (sku == null) {
            throw new BusinessException("SKU不存在");
        }
        ProductSku updateSku = new ProductSku();
        updateSku.setId(id);
        updateSku.setAdminStatus(enabled ? 1 : 0);
        return baseMapper.updateById(updateSku) == 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchUpdateSkuStatus(List<Long> skuIds, Boolean enabled) {
        if (CollectionUtils.isEmpty(skuIds)) {
            return false;
        }
        ProductSku updateSku = new ProductSku();
        updateSku.setAdminStatus(enabled ? 1 : 0);
        return update(updateSku, new LambdaQueryWrapper<ProductSku>()
                .in(ProductSku::getId, skuIds));
    }

    @Override
    public IPage<ProductSku> pagePendingSkus(Page<ProductSku> page) {
        // Since we removed audit functionality, return empty page
        return page.setRecords(Collections.emptyList());
    }

    @Override
    public void auditSku(Long id, Integer auditStatus, String auditComment) {
        // Since we removed audit functionality, this method is now a no-op
        log.warn("Audit functionality has been removed");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean lockStock(Long skuId, Integer quantity) {
        log.debug("Locking stock for SKU: {}, quantity: {}", skuId, quantity);
        return update()
            .setSql("lock_stock = lock_stock + " + quantity)
            .setSql("stock = stock - " + quantity)
            .setSql("version = version + 1")
            .eq("id", skuId)
            .ge("stock", quantity)
            .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unlockStock(Long skuId, Integer quantity) {
        log.debug("Unlocking stock for SKU: {}, quantity: {}", skuId, quantity);
        return update()
            .setSql("lock_stock = lock_stock - " + quantity)
            .setSql("stock = stock + " + quantity)
            .setSql("version = version + 1")
            .eq("id", skuId)
            .ge("lock_stock", quantity)
            .update();
    }

    @Override
    public boolean checkStock(Long skuId, Integer quantity) {
        ProductSku sku = getById(skuId);
        return sku != null && sku.getStock() >= quantity;
    }
} 